#include "MemoryStream.h"
#include "Exception.h"

using namespace Woo;
using namespace Woo::IO;

MemoryStream::MemoryStream() :
	m_vPos(0),
	m_hasClosed(false)
{
}

MemoryStream::MemoryStream(const Byte* buffer, UInt32 bufferSize) :
	m_vPos(bufferSize),
	m_hasClosed(false)
{
	m_vBuffer = vector<Byte>(bufferSize);
	memcpy(&m_vBuffer.at(0),  buffer, bufferSize);
}

MemoryStream::~MemoryStream()
{
}

UInt32 MemoryStream::GetLength()
{
	if(m_hasClosed)
	{
		throw StreamClosedException("stream has closed.", __FILE__, __LINE__);
	}
	return m_vBuffer.size();
}

UInt32 MemoryStream::GetPosition()
{
	if(m_hasClosed)
	{
		throw StreamClosedException("stream has closed.", __FILE__, __LINE__);
	}
	return m_vPos;
}

void MemoryStream::SetPosition(UInt32 position)
{
	if(m_hasClosed)
	{
		throw StreamClosedException("stream has closed.", __FILE__, __LINE__);
	}
	if(position > m_vBuffer.size())
		throw IndexOutOfRangeException("Memory stream set position is larger than buffer length.", __FILE__, __LINE__);

	m_vPos = position;
}

UInt32 MemoryStream::Write(const Byte* buffer, UInt32 bufferSize)
{
	if(m_hasClosed)
	{
		throw StreamClosedException("stream has closed.", __FILE__, __LINE__);
	}

	if(m_vPos == m_vBuffer.size())
	{
		m_vBuffer.insert(m_vBuffer.end(), bufferSize, 0);
	}
	else
	{
		UInt32 unsz = m_vBuffer.size() - m_vPos;
		if(unsz < bufferSize)
		{
			m_vBuffer.insert(m_vBuffer.end(), bufferSize - unsz, 0);
		}
	}
	memcpy(&m_vBuffer.at(m_vPos), buffer, bufferSize);
	m_vPos += bufferSize;
}

UInt32 MemoryStream::Read(Byte* buffer, UInt32 bufferSize)
{
	if(m_hasClosed)
	{
		throw StreamClosedException("stream has closed.", __FILE__, __LINE__);
	}
	
	if(m_vPos == m_vBuffer.size())
	{
		return 0;
	}
	else
	{
		UInt32 unsz = m_vBuffer.size() - m_vPos;
		if(unsz < bufferSize)
		{
			memcpy(buffer, &m_vBuffer.at(m_vPos), unsz);
			return unsz;
		}
		else
		{
			memcpy(buffer, &m_vBuffer.at(m_vPos), bufferSize);
			return bufferSize;
		}
	}
}

void MemoryStream::Close()
{
	m_hasClosed = true;
}

bool MemoryStream::IsClosed()
{
	return m_hasClosed;
}

bool MemoryStream::CanRead()
{
	if(m_hasClosed)
	{
		return false;
	}
	return true;
}

bool MemoryStream::CanWrite()
{
	if(m_hasClosed)
	{
		return false;
	}
	return true;
}
